#include <iostream>
#include <string>
#include <gmp.h>
#include <gmpxx.h>
#include <string>
#include <fstream>
#include <sstream>

#define BITS_PER_DIGIT 3.32192809488736234787;

void gauss_legendre() {
	mpf_class *a0, *a1, *b0, *b1, *t0, *t1, *p0, *p1, *pi0, *pi1;
	mpf_class eq_cmp("1E-10000000");
	
	mpf_class tmp;
	int cmpr;
	int iteration = 0;

	a0 = new mpf_class(1);
	b0 = new mpf_class(2);
	*b0 = sqrt(*a0 / *b0);
	t0 = new mpf_class(0.25);
	p0 = new mpf_class(1);

	a1 = new mpf_class();
	b1 = new mpf_class();
	t1 = new mpf_class();
	p1 = new mpf_class();

	pi0 = new mpf_class();
	pi1 = new mpf_class();

	tmp = *a0 + *b0;
	*pi0 = (tmp * tmp) / (4. * *t0);


	do {		

		std::stringstream ss;
		ss << "GLST_Iteracao_" << iteration << ".txt";
		std::fstream file;
		file.open(ss.str().c_str(), std::fstream::out);
		file.setf(std::ios::fixed, std::ios::floatfield);
		file.precision(10000000);
		file << *pi0 << std::endl;

		std::cout << "Comecando a calcular a iteracao " << ++iteration << std::endl;

		*a1 = (*a0 + *b0) / 2;

		*b1 = sqrt(*a0 * *b0);

		tmp = *a0 - *a1;
		*t1 = *t0 - *p0 * (tmp * tmp);

		*p1 = 2 * *p0;

		tmp = *a1 + *b1;
		*pi1 = (tmp * tmp) / (4 * *t1);

		cmpr = cmp(abs(*pi1 - *pi0), eq_cmp);

		std::swap(a0, a1);
		std::swap(b0, b1);
		std::swap(t0, t1);
		std::swap(p0, p1);
		std::swap(pi0, pi1);


	} while (cmpr >= 0);

	{
		std::stringstream ss;
		ss << "GLST_Iteracao_" << iteration << "_PI_FINAL.txt";
		std::fstream file;
		file.open(ss.str().c_str(), std::fstream::out);
		file.setf(std::ios::fixed, std::ios::floatfield);
		file.precision(10000000);
		file << *pi0 << std::endl;
		std::cout << "PI calculado com sucesso em " << iteration << " iteracoes\n";
	}

	delete a0;
	delete a1;
	delete b0;
	delete b1;
	delete t0;
	delete t1;
	delete p0;
	delete p1;
	delete pi0;
	delete pi1;
}

int main(int argc, char *argv[]) {
	mpf_set_default_prec((long int)(3.32192809488736234787 * 10000100.0));

	std::cout << "Bem vindo ao programa que calcula o PI!\n";
	std::cout << "10 milhoes de casas do pi serao calculadas!\n";
	std::cout << "Arquivos de prefixo \"GLST_\" serao criados\n";

	// std::cout.setf(std::ios::fixed, std::ios::floatfield);
	// std::cout.precision(10000000);

	gauss_legendre();
	return 0;
}
